﻿using System;
using System.Collections.Generic;
using System.Collections.ObjectModel;
using System.Diagnostics;
using System.Linq;
using System.Windows;
#if PC
using OverlakeWSTester;
#endif

namespace OverlakeApp.ViewModels
{
#if PC
    using AppService = OverlakeWSTester.AppService;
#endif

    /// <summary>
    /// The main MVVM ViewModel for the app.
    /// </summary>
    public class OverlakeViewModel : ViewModelBase
    {
        private const string TestUserAgent = "WpfTestApp";

        public delegate void MsgboxShow(string msg);
        public delegate MessageBoxResult MsgboxShow2(string msg, string msg2, MessageBoxButton btn);
        public MsgboxShow MessageBoxWrapper;
        public MsgboxShow2 MessageBoxWrapper2;

        private bool networkIsInitialized = false;
        private static AppService.OverlakeAppService_1_0SoapClient _soapClient;

        #region Nested Classes

        /// <summary>
        /// A simple pair that represents a date and its corresponding letter day.
        /// </summary>
        public class LetterDayPair : ViewModelBase
#if !PC
, WPControls.ISupportCalendarItem
#endif
        {
            private String _DayNote;
            /// <summary>
            /// The letter day of the date.
            /// </summary>
            public String DayNote
            {
                get
                {
                    return this._DayNote;
                }
                set
                {
                    if (this._DayNote != value)
                    {
                        this._DayNote = value;
                        this.OnPropertyChanged("DayNote");
                    }
                }
            }

            private DateTime _CalendarItemDate;
            /// <summary>
            /// The date.
            /// </summary>
            public DateTime CalendarItemDate
            {
                get
                {
                    return this._CalendarItemDate;
                }
                set
                {
                    if (this._CalendarItemDate != value)
                    {
                        this._CalendarItemDate = value;
                        this.OnPropertyChanged("CalendarItemDate");
                    }
                }
            }
        }

        #endregion

        #region Methods
        #region Constructors

        /// <summary>
        /// The default constructor that sets up the app and kicks off the loading process.
        /// </summary>
        public OverlakeViewModel() : this(true) { }

        /// <summary>
        /// A constructor that allows for NOT loading from the network, to only use cached data. (mostly for the homescreen tile)
        /// </summary>
        /// <param name="loadFromNetwork">If true, new data will be loaded from the network.</param>
        public OverlakeViewModel(bool loadFromNetwork)
        {
            LoginPressed = false;
            this.WeatherData = new WeatherDataModel();

#if PC
            HttpUserAgentEndpointBehavior.UserAgent = TestUserAgent;
#endif



            if (IsInDesignMode)
                return;


#if RELEASE
            this.AllowDevMode = false;
#endif
#if DEBUG
            this.AllowDevMode = true;
#endif
            this.DevModeEnabled = Debugger.IsAttached;

            if (Calendar == null)
                Calendar = new CalendarFactory(this);

            if (_soapClient == null)
            {
                _soapClient = new AppService.OverlakeAppService_1_0SoapClient();
#if PC
                _soapClient.Endpoint.Behaviors.Add(new HttpUserAgentEndpointBehavior());
#endif
            }

            this.LoginService = new LoginService();
            this.LoginService.LoginAsyncCompleted += LoginService_LoginStateChanged;

            _soapClient.GetAssembledScheduleCompleted += SOAPClient_ActionCompleted;
            _soapClient.GetLunchDataCompleted += SOAPClient_ActionCompleted;
            _soapClient.GetTeachersCompleted += SOAPClient_ActionCompleted;
            _soapClient.GetWeatherDataCompleted += SOAPClient_ActionCompleted;
            _soapClient.GetWeatherImageCompleted += SOAPClient_ActionCompleted;
            _soapClient.SubmitErrorCompleted += SOAPClient_ActionCompleted;
            _soapClient.TestCompleted += SOAPClient_ActionCompleted;

            this.Calendar.LoadCalendarCompleted += Calendar_LoadCalendarCompleted;
            this.Calendar.PropertyChanged += Calendar_PropertyChanged;

            if (loadFromNetwork)
                this.StartLoadingAsync();
        }

        #endregion

        #region Event Handlers
        void Calendar_PropertyChanged(object sender, System.ComponentModel.PropertyChangedEventArgs e)
        {
            this.Log("Calendar_PropertyChanged begin.");

            //Settings.Save();

            if (e.PropertyName == "CalendarItems")
            {
                this.OnPropertyChanged("CalendarItems");
                this.OnPropertyChanged("LetterDayCalendar");
            }

            this.Log("Calendar_PropertyChanged complete.");
        }

        void Calendar_LoadCalendarCompleted(object sender, CalendarFactory.LoadCalendarCompletedEventArgs e)
        {
            this.OutstandingNetworkRequests--;
            this.OnPropertyChanged("CurrentLetterDay");
            this.Log("LoadRotationMonth complete.");

            //this.OutstandingNetworkRequests++;
            //e.Month = e.Month.AddMonths(1);
            //this.Log("LoadRotationMonth begin for " + e.Month.Year + "-" + e.Month.Month);
            //this.Calendar.LoadMonth(e.Month);
        }

        void SOAPClient_ActionCompleted(object sender, System.ComponentModel.AsyncCompletedEventArgs e)
        {
            this.OutstandingNetworkRequests--;

            this.Log("ActionCompleted with " + e.GetType());

            try
            {
                if (e is AppService.TestCompletedEventArgs)
                {
                    this.Log("Test Completed");

                    this.networkIsInitialized = true;

                    if ((e as AppService.TestCompletedEventArgs).Result == "Overlake")
                        this.LoadNonLoginData();
                }
                else if (e is AppService.GetAssembledScheduleCompletedEventArgs)
                {
                    this.Log("Schedule Completed");
                    this.DaySchedules = (e as AppService.GetAssembledScheduleCompletedEventArgs).Result.Schedule;
                    this.Sections = (e as AppService.GetAssembledScheduleCompletedEventArgs).Result.Sections;
                }
                else if (e is AppService.GetLunchDataCompletedEventArgs)
                {
                    this.Log("LunchData Completed");
                    this.Lunches = (e as AppService.GetLunchDataCompletedEventArgs).Result;
                }
                else if (e is AppService.GetTeachersCompletedEventArgs)
                {
                    this.Log("TeacherData Completed");
                    this.Teachers = (e as AppService.GetTeachersCompletedEventArgs).Result;
                }
                else if (e is AppService.GetWeatherDataCompletedEventArgs)
                {
                    this.Log("WeatherData Completed");
                    var e2 = e as AppService.GetWeatherDataCompletedEventArgs;
                    this.WeatherData.Temperature = e2.Result.Temperature;
                }
                else if (e is AppService.GetWeatherImageCompletedEventArgs)
                {
                    this.Log("WeatherImage Completed");
                    this.WeatherData.WeatherImageBytes = (e as AppService.GetWeatherImageCompletedEventArgs).Result;
                }
                else if (e is AppService.SubmitErrorCompletedEventArgs)
                {
                    Settings.AddOrUpdateValue("LastError", null);
                }
                else
                {
                    Debugger.Break();
                }
            }
            catch
            {
                _soapClient.Abort();
                _soapClient = new AppService.OverlakeAppService_1_0SoapClient();
#if PC
                _soapClient.Endpoint.Behaviors.Add(new HttpUserAgentEndpointBehavior());
#endif

                this.networkIsInitialized = false;

                Dispatcher.BeginInvoke(
                    new Func<MessageBoxResult>(() =>
                          this.MessageBoxWrapper2("There was an error connecting to Overlake's servers.  ", "No connection...",
                                                  System.Windows.MessageBoxButton.OK)));
            }
        }

        #endregion

        #region Network Test
        private void StartLoadingAsync()
        {
            this.OutstandingNetworkRequests++;
            this.Log("Test Begin");
            _soapClient.TestAsync();
        }
        #endregion

        #region Data Loading

        /// <summary>
        /// This is where we load any data that does NOT require a login.
        /// </summary>
        private void LoadNonLoginData()
        {
            // Attempt to login
            this.OutstandingNetworkRequests++;
            this.Log("Login begin");
            this.LoginService.LoginAsync();

            // Weather temp/humidity
            this.OutstandingNetworkRequests++;
            this.Log("WeatherData begin");
            _soapClient.GetWeatherDataAsync();

            // Weather condition icon
            this.OutstandingNetworkRequests++;
            this.Log("WeatherImage begin");
            _soapClient.GetWeatherImageAsync();

            // Lunch table
            this.OutstandingNetworkRequests++;
            this.Log("LunchData begin");
            _soapClient.GetLunchDataAsync();

            this.OutstandingNetworkRequests++;
            this.Log("LoadRotationMonth begin for " + DateTime.Now.Year + "-" + DateTime.Now.Month);
            this.Calendar.LoadMonth(DateTime.Now.Month, DateTime.Now.Year);

            //this._networkIsInitialized = true;

            SubmitError();
        }

        private void SubmitError()
        {
            if (Settings.GetValueOrDefault<AppService.ErrorReport>("LastError", null) != null)
            {
                var err = Settings.GetValueOrDefault<AppService.ErrorReport>("LastError", null);
                this.OutstandingNetworkRequests++;
                _soapClient.SubmitErrorAsync(err);
            }
        }


        private bool LoginPressed { get; set; }

        /// <summary>
        /// Fires when a login completes.
        /// </summary>
        public event EventHandler<AppService.LoginCompletedEventArgs> LoginCompleted;

        /// <summary>
        /// This is fired whenever a login is completed on the LoginService object. This is where we load any data that DOES require a login.
        /// </summary>
        /// <param name="sender">The object that raised the event.</param>
        /// <param name="e">The information about the event.</param>
        void LoginService_LoginStateChanged(object sender, AppService.LoginCompletedEventArgs e)
        {
            this.OutstandingNetworkRequests--;

            this.Log("Login completed with State = " + e.Result.State);

            if (LoginPressed)
            {
                Dispatcher.BeginInvoke(new Action(() =>
                                                 {
                                                     if (this.LoginCompleted != null)
                                                         this.LoginCompleted(this, e);
                                                 }));
            }

            if (e.Result.State == AppService.LoginState.Success)
            {
                if (LoginPressed)
                {
                    LoginPressed = false;
                    this.MessageBoxWrapper2("You're logged in!", "Success!", System.Windows.MessageBoxButton.OK);
                }

                // Classes/Schedule data
                this.OutstandingNetworkRequests++;
                this.Log("Schedule begin!");
                _soapClient.GetAssembledScheduleAsync(this.LoginService.UserInfo.Key, this.LoginService.UserInfo.StudentID);

                // Teacher list.  We don't get images because those are bound so Silverlight deals with it
                this.OutstandingNetworkRequests++;
                this.Log("TeacherData begin!");
                _soapClient.GetTeachersAsync(this.LoginService.UserInfo.Key);
            }
            else
            {
                if (!(String.IsNullOrEmpty(this.LoginService.Username) || String.IsNullOrEmpty(this.LoginService.Password)))
                {
                    this.MessageBoxWrapper2(e.Result.ErrorMessage, "Error...", System.Windows.MessageBoxButton.OK);
                }
            }
        }

        #endregion

        #endregion

        #region Properties

        #region Log
        //[Conditional("DEBUG")]
        internal void Log(string text)
        {
            string line = DateTime.Now.ToString("HH:mm:ss.fff") + ": " + text;
            LogText += line + "\n";
#if DEBUG
            if (Debugger.IsAttached)
                Debug.WriteLine(line);
#endif
        }

        private String _LogText;
        /// <summary>
        /// The text currently contained in the log.
        /// </summary>
        public String LogText
        {
            get
            {
                return _LogText;
            }
            protected set
            {
                if (_LogText == value) return;
                _LogText = value;
                this.OnPropertyChanged("LogText");
            }
        }
        #endregion

        #region Dev Mode
        private bool _DevModeEnabled;
        /// <summary>
        /// If enabled, this enables debugging features like logging.
        /// </summary>
        public bool DevModeEnabled
        {
            get
            {
                return this._DevModeEnabled;
            }
            set
            {
                if (this._DevModeEnabled == value) return;
                this._DevModeEnabled = value;
                this.OnPropertyChanged("DevModeEnabled");
            }
        }

        /// <summary>
        /// If enabled, this allows DevModeEnabled to be true.
        /// </summary>
        private bool _AllowDevMode;
        public bool AllowDevMode
        {
            get
            {
                return this._AllowDevMode;
            }
            set
            {
                if (this._AllowDevMode == value) return;

                this._AllowDevMode = value;
                this.OnPropertyChanged("AllowDevMode");
            }
        }


        private bool _SuperDebugEnabled;
        /// <summary>
        /// Even more debug.  Use with caution.
        /// </summary>
        public bool SuperDebugEnabled
        {
            get
            {
                return this._SuperDebugEnabled;
            }
            set
            {
                if (this._SuperDebugEnabled != value)
                {
                    this._SuperDebugEnabled = value;
                    this.OnPropertyChanged("SuperDebugEnabled");
                }
            }
        }

        #endregion

        #region Calendar

        private AppService.CalendarEvent _CurrentCalendarEvent;
        /// <summary>
        /// The currently selected calendar event.
        /// </summary>
        public AppService.CalendarEvent CurrentCalendarEvent
        {
            get
            {
                return this._CurrentCalendarEvent;
            }
            set
            {
                if (this._CurrentCalendarEvent != value)
                {
                    this._CurrentCalendarEvent = value;
                    this.OnPropertyChanged("CurrentCalendarEvent");
                }
            }
        }

        private CalendarFactory _Calendar;
        /// <summary>
        /// The calendar factory that manages downloading and caching the calendar.
        /// </summary>
        public CalendarFactory Calendar
        {
            get
            {
                return this._Calendar;
            }
            set
            {
                if (this._Calendar != value)
                {
                    this._Calendar = value;
                    this.OnPropertyChanged("Calendar");
                }
            }
        }

        /// <summary>
        /// Today's letter day.
        /// </summary>
        public string CurrentLetterDay
        {
            get
            {
                //DateTime date = DateTime.Parse("2012-08-28");

                DateTime date = DateTime.Now.Date;

                if (this.LetterDayCalendar.Any(d => d.CalendarItemDate.Equals(date)))
                {
                    return this.LetterDayCalendar.First(d => d.CalendarItemDate.Equals(date)).DayNote;
                }
                else
                {
                    return "no school";
                }
            }
        }

        /// <summary>
        /// The list of objects that form the 
        /// </summary>
        public IEnumerable<
#if PC
LetterDayPair
#else
WPControls.ISupportCalendarItem
#endif
> LetterDayCalendar
        {
            get
            {
                if (ViewModelBase.IsInDesignMode)
                {
                    yield break;
                }

                foreach (var c in from f in this.Calendar.CalendarItems
                                  where f.IsLetterDay
                                  select f)
                    yield return new LetterDayPair { CalendarItemDate = c.StartTime, DayNote = c.Name };

            }
        }

        private DateTime _SelectedDate;
        /// <summary>
        /// The date that is currently selected on the calendar.
        /// </summary>
        public DateTime SelectedDate
        {
            get
            {
                return this._SelectedDate;
            }
            set
            {
                if (this._SelectedDate != value)
                {
                    this._SelectedDate = value;
                    this.OnPropertyChanged("SelectedDate");
                    //this.OnPropertyChanged("CurrentDayCalendarItems");
                }
            }
        }

        /// <summary>
        /// The calendar items that collide with the currently selected date.
        /// </summary>
        public IEnumerable<AppService.CalendarEvent> CurrentDayCalendarItems
        {
            get
            {
                var NewCurrentDay = new List<AppService.CalendarEvent>();

                foreach (var c in this.Calendar.CalendarItems)
                {
                    if (c.StartTime < this.SelectedDate)        // If it starts before the selected day
                    {
                        if (c.EndTime >= this.SelectedDate)     // If it concludes on or after the selected day
                        {
                            NewCurrentDay.Add(c);               // Pick it if so
                        }
                    }
                    else if (c.StartTime < this.SelectedDate.AddDays(1))    // If it starts ON the day [day, day+1]
                    {
                        NewCurrentDay.Add(c);
                    }
                }

                return NewCurrentDay.OrderBy(c => c.StartTime);
            }
        }
        #endregion

        #region Network Requests
        private bool _OutstandingNetworkRequestsLock;
        private int _OutstandingNetworkRequests;
        /// <summary>
        /// The number of network requests that have yet to return.
        /// </summary>
        public int OutstandingNetworkRequests
        {
            get
            {
                return this._OutstandingNetworkRequests;
            }
            protected set
            {
                while (_OutstandingNetworkRequestsLock) ;
                this._OutstandingNetworkRequestsLock = true;

                this.Log("Outstanding set to " + value);

                if (this.SuperDebugEnabled)
                {
                    var tr = new StackTrace();
                    var sb = new System.Text.StringBuilder();
                    int c = 5;
                    foreach (var f in tr.GetFrames())
                    {
                        c--;
                        if (c == 0) break;

                        sb.AppendLine('\t' + f.GetMethod().ToString());
                    }

                    this.Log('\n' + sb.ToString());
                }

                if (this._OutstandingNetworkRequests != value)
                {
                    this._OutstandingNetworkRequests = value;
                    this.OnPropertyChanged("OutstandingNetworkRequests");
                    this.OnPropertyChanged("IsLoading");
                }

                this._OutstandingNetworkRequestsLock = false;
            }
        }

        /// <summary>
        /// Returns true if there are outstanding requests that we are waiting for.
        /// </summary>
        public bool IsLoading
        {
            get
            {
                return this.OutstandingNetworkRequests != 0;
            }
        }
        #endregion

        #region Login
        private LoginService _LoginService;
        /// <summary>
        /// The login service that manages credentials/keys for login.
        /// </summary>
        public LoginService LoginService
        {
            get
            {
                return this._LoginService;
            }
            private set
            {
                if (this._LoginService == value) return;
                this._LoginService = value;
                this.OnPropertyChanged("LoginService");
            }
        }
        #endregion

        #region Teachers
        /// <summary>
        /// The collection of teachers.
        /// </summary>
        public ObservableCollection<AppService.Teacher> Teachers
        {
            get
            {
                return Settings.GetValueOrDefault("Teachers", new ObservableCollection<AppService.Teacher>());
            }
            protected set
            {
                if (Settings.AddOrUpdateValue("Teachers", value))
                {
                    this.OnPropertyChanged("Teachers");
                }
            }
        }

        private AppService.Teacher _SelectedTeacher;
        /// <summary>
        /// The teacher that is currently selected to view detail.
        /// </summary>
        public AppService.Teacher SelectedTeacher
        {
            get
            {
                return this._SelectedTeacher;
            }
            set
            {
                if (this._SelectedTeacher == value) return;

                this._SelectedTeacher = value;
                this.OnPropertyChanged("SelectedTeacher");
            }
        }
        #endregion

        #region Lunch
        /// <summary>
        /// The lunch object for today's lunch, or <value>null</value> if there is no lunch today.
        /// </summary>
        public string CurrentLunch
        {
            get
            {
                if (this.Lunches == null)
                {
                    return "Loading...";
                }
                else if (this.Lunches.Count == 0)
                {
                    return "lunch calendar empty";
                }
                else if (this.Lunches.Any(l => l.Date.Date == DateTime.Today))
                {
                    return this.Lunches.First(l => l.Date.Date == DateTime.Today).LunchName;
                }
                else
                {
                    return "no lunch today";
                }

                //return "It's a test!";
            }
        }

        /// <summary>
        /// The collection of lunches.
        /// </summary>
        public ObservableCollection<AppService.Lunch> Lunches
        {
            get
            {
                var retval = Settings.GetValueOrDefault("Lunches", new ObservableCollection<AppService.Lunch>());
                return retval;
            }
            protected set
            {
                if (Settings.AddOrUpdateValue("Lunches", value))
                {
                    this.OnPropertyChanged("Lunches");
                    // This might change CurrentLunch too, so update it too.
                    this.OnPropertyChanged("CurrentLunch");
                }
            }
        }
        #endregion

        #region Weather
        private WeatherDataModel _WeatherData;
        /// <summary>
        /// The information about the current weather at Overlake.
        /// </summary>
        public WeatherDataModel WeatherData
        {
            get
            {
                return this._WeatherData;
            }
            set
            {
                if (this._WeatherData != value)
                {
                    this._WeatherData = value;
                    this.OnPropertyChanged("WeatherData");
                }
            }
        }
        #endregion

        #region Schedulue

        private AppService.Section _CurrentSection;
        /// <summary>
        /// The currently selected 
        /// </summary>
        public AppService.Section CurrentSection
        {
            get
            {
                return this._CurrentSection;
            }
            set
            {
                if (this._CurrentSection != value)
                {
                    this._CurrentSection = value;
                    this.OnPropertyChanged("CurrentSection");
                    this.OnPropertyChanged("TeacherForCurrentSection");

                }
            }
        }

        /// <summary>
        /// The teacher associated with the current section.
        /// </summary>
        public AppService.Teacher TeacherForCurrentSection
        {
            get
            {
                if (CurrentSection.FacultyIDs.Count == 0)
                    return null;
                else
                    if (this.Teachers.Any(t => t.FacultyId == CurrentSection.FacultyIDs[0]))
                        return this.Teachers.First(t => t.FacultyId == CurrentSection.FacultyIDs[0]);
                    else
                        return null;
            }
        }

        /// <summary>
        /// The sections that the user is enrolled in for all semesters.
        /// </summary>
        public ObservableCollection<AppService.Section> Sections
        {
            get
            {
                return Settings.GetValueOrDefault("Sections", new ObservableCollection<AppService.Section>());
            }
            set
            {
                if (Settings.AddOrUpdateValue("Sections", value))
                {
                    this.OnPropertyChanged("Sections");
                }
            }
        }

        /// <summary>
        /// A list of days, each of which contains a collection of classes for that day, and the day name.
        /// </summary>
        public ObservableCollection<AppService.ScheduleDay> DaySchedules
        {
            get
            {
                return Settings.GetValueOrDefault("DaySchedules", new ObservableCollection<AppService.ScheduleDay>());
            }
            set
            {
                if (Settings.AddOrUpdateValue("DaySchedules", value))
                {
                    this.OnPropertyChanged("DaySchedules");
                }
            }
        }
        #endregion

        #endregion

        #region Commands

        private RelayCommand _LoginCommand;
        /// <summary>
        /// When activated, the LoginService is asked to log in with the current username and password.
        /// </summary>
        public RelayCommand LoginCommand
        {
            get
            {
                if (this._LoginCommand == null)
                    this._LoginCommand = new RelayCommand(state =>
                    {
                        this.OutstandingNetworkRequests++;
                        this.LoginPressed = true;
                        this.LoginService.LoginAsync();
                    });

                return this._LoginCommand;
            }
        }


        private RelayCommand _RefreshCommand;
        /// <summary>
        /// Refreshes the data from the server.
        /// </summary>
        public RelayCommand RefreshCommand
        {
            get
            {
                if (this._RefreshCommand == null)
                    this._RefreshCommand = new RelayCommand(
                    (state) =>
                    {
                        this.Log("Refresh Command pressed!");

                        this.StartLoadingAsync();
                        //this.LoginCommand.Execute(null);
                    });

                return this._RefreshCommand;
            }
        }

#if !PC
        private RelayCommand _MonthChangedCommand;
        /// <summary>
        /// Triggered when the current month in the calendar is changed, so we can load it.
        /// </summary>
        public RelayCommand MonthChangedCommand
        {
            get
            {
                if (this._MonthChangedCommand == null)
                    this._MonthChangedCommand = new RelayCommand(
                    (state) =>
                    {
                        var c = state as WPControls.ISelectableMonthDate;
                        int month = c.SelectedMonth;
                        int year = c.SelectedYear;
                        this.OutstandingNetworkRequests++;
                        this.Log("LoadRotationMonth begin for " + year + "-" + month);
                        this.Calendar.LoadMonth(month, year);
                    }, state => this.networkIsInitialized);

                return this._MonthChangedCommand;
            }
        }
#endif

        private RelayCommand _ResetEverythingCommand;
        /// <summary>
        /// Resets everything, then closes the app HACK HACK HACK HACK HACK.
        /// </summary>
        public RelayCommand ResetEverythingCommand
        {
            get
            {
                if (this._ResetEverythingCommand == null)
                    this._ResetEverythingCommand = new RelayCommand(
                    (state) =>
                    {
                        var result = this.MessageBoxWrapper2("This will reset everything in the app, and empty all the caches.  The app will restart if you do this.", "Are you sure?", System.Windows.MessageBoxButton.OKCancel);
                        switch (result)
                        {
                            case System.Windows.MessageBoxResult.OK:
                                Settings.Clear();
                                throw new AppClosureException();
                            case System.Windows.MessageBoxResult.Cancel:


                                return;
                        }
                    });

                return this._ResetEverythingCommand;
            }
        }

        private RelayCommand _ExceptionCommand;
        /// <summary>
        /// Triggers an exception, specifically a DivideByZeroException, for testing purposes only.
        /// </summary>
        public RelayCommand ExceptionCommand
        {
            get
            {
                if (this._ExceptionCommand == null)
                    this._ExceptionCommand = new RelayCommand(
                    (state) =>
                    {
                        // ReSharper disable ConvertToConstant.Local
                        int i = 0;
                        int n = 1 / i;
                        // ReSharper restore ConvertToConstant.Local
                    });

                return this._ExceptionCommand;
            }
        }

        #endregion
    }
}